package cn.liziguo.tank.script;

import cn.liziguo.tank.buff.InvincibleEffect;
import cn.liziguo.tank.buff.ShipEffect;
import cn.liziguo.tank.buff.SpeedingEffect;
import cn.liziguo.tank.config.GameConfig;
import cn.liziguo.tank.constants.GameEnum;
import cn.liziguo.tank.constants.ImageConst;
import cn.liziguo.tank.factory.EffectsFactory;
import cn.liziguo.tank.factory.ItemFactory;
import cn.liziguo.tank.script.enemy.EnemyComponent;
import cn.liziguo.tank.script.player.PlayerComponent;
import cn.liziguo.tank.util.CollidingUtils;
import cn.liziguo.tank.util.LocalTimer;
import cn.liziguo.tank.util.Time;
import cn.liziguo.tank.vector.Vector2;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.core.math.Vec2;
import com.almasb.fxgl.core.util.LazyValue;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.dsl.components.EffectComponent;
import com.almasb.fxgl.dsl.components.HealthIntComponent;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.EntityGroup;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.texture.Texture;

import java.util.List;
import java.util.Optional;

/**
 * @author Liziguo
 * @date 2022-07-09 16:57:58
 */
public abstract class BaseTankComponent extends Component {
    public static final GameEnum[] NOT_ARMED_SHIP = {GameEnum.BORDER, GameEnum.HOME, GameEnum.SEA, GameEnum.BRICK, GameEnum.STONE, GameEnum.PLAYER, GameEnum.ENEMY};
    public static final GameEnum[] ARMED_SHIP = {GameEnum.BORDER, GameEnum.HOME, GameEnum.BRICK, GameEnum.STONE, GameEnum.PLAYER, GameEnum.ENEMY};

    protected final LazyValue<EntityGroup> listLazyCollision = new LazyValue<>(() -> FXGL.getGameWorld().getGroup(NOT_ARMED_SHIP));
    protected final LazyValue<EntityGroup> listLazyCollisionShip = new LazyValue<>(() -> FXGL.getGameWorld().getGroup(ARMED_SHIP));

    protected final LocalTimer shootTimer = new LocalTimer();
    protected final long shootCd;

    protected final LocalTimer skillTimer = new LocalTimer();
    protected final long skillCd;

    protected EffectComponent effectComponent;
    protected HealthIntComponent healthIntComponent;

    /**
     * 移动速度
     */
    public double speed;

    /**
     * 坦克方向
     */
    public Vec2 vector = Vector2.UP;

    /**
     * 子弹等级
     */
    public int bulletLevel = GameConfig.BULLET_LEVEL_DEFAULT;

    /**
     * 是否可以水面行走
     */
    public boolean isArmedShip;

    /**
     * 技能数量
     */
    public int skillCount;

    public BaseTankComponent(long shootCd, long skillCd) {
        this.shootCd = shootCd;
        this.skillCd = skillCd;
    }

    public void giveArmedShip() {
        effectComponent.startEffect(new ShipEffect());
        if (isArmedShip) {
            return;
        }
        isArmedShip = true;
//        ImageView imageView = new ImageView(FXGL.image(ImageConst.ITEM_ARMED_SHIP));
//        imageView.setX(entity.getWidth() / 2 - imageView.getImage().getWidth() / 2);
//        imageView.setY(entity.getHeight() / 2 - imageView.getImage().getHeight() / 2);
        Texture imageView = FXGL.texture(ImageConst.ARMED_SHIP);
        imageView.setTranslateX(entity.getWidth() / 2 - imageView.getWidth() / 2);
        imageView.setTranslateY(entity.getHeight() / 2 - imageView.getHeight() / 2);
        entity.getViewComponent().addChild(imageView);
    }

    public void giveInvincible() {
        effectComponent.startEffect(new InvincibleEffect());
    }

    public void giveSpeeding() {
        effectComponent.startEffect(new SpeedingEffect());
    }

    public void bulletLevelUp() {
        final int level = bulletLevel + 1;
        bulletLevel = Math.min(level, GameConfig.BULLET_LEVEL_MAX);
    }

    public boolean isInvincible() {
        return effectComponent.hasEffect(InvincibleEffect.class);
    }

    public void moveForward() {
        final double distance = speed * Time.deltaTime;
        float vx = vector.x;
        float vy = vector.y;
        final double distanceX = vx * distance;
        final double distanceY = vy * distance;

        final Entity entity = this.entity;
        final double width = entity.getWidth();
        final double height = entity.getHeight();
        final double absDistanceX = FXGLMath.abs(distanceX);
        final double absDistanceY = FXGLMath.abs(distanceY);

        double moved = 0;
        List<Entity> list = isArmedShip ? listLazyCollisionShip.get().getEntitiesCopy() : listLazyCollision.get().getEntitiesCopy();
        for (int i = 0; i + width < absDistanceX; i += width, moved += width) {
            entity.translateX(vx * width);
            if (CollidingUtils.isColliding(entity, list) != null) {
                entity.translateX(-vx * width);
            }
        }
        for (int i = 0; i + height < absDistanceY; i += height, moved += height) {
            entity.translateY(vy * height);
            if (CollidingUtils.isColliding(entity, list) != null) {
                entity.translateY(-vy * height);
            }
        }

        final double remaining = distance - moved;
        entity.translate(vx * remaining, vy * remaining);
        if (CollidingUtils.isColliding(entity, list) != null) {
            entity.translate(-vx * remaining, -vy * remaining);
            for (int i = 0, len = (int) remaining; i < len; i++) {
                entity.translate(vx, vy);
                if (CollidingUtils.isColliding(entity, list) != null) {
                    entity.translate(-vx, -vy);
                    break;
                }
            }
        }
    }

    public void underAttack(int attack) {
        if (effectComponent.hasEffect(InvincibleEffect.class)) {
            return;
        }
        healthIntComponent.damage(attack);
        if (healthIntComponent.isZero()) {
            entity.removeFromWorld();
            EffectsFactory.createBoom(entity.getCenter());
            // 坦克被销毁时概率掉落道具
            if (FXGLMath.randomBoolean(GameConfig.ITEM_DROP_PROBABILITY)) {
                ItemFactory.createRandomItem();
            }
        }
    }

    public void restore(int hp) {
        healthIntComponent.restore(hp);
    }

    public void shoot() {
        if (shootTimer.elapsed(shootCd)) {
            onShoot();
            shootTimer.capture();
        }
    }

    public void skill() {
        if (skillCount > 0 && skillTimer.elapsed(skillCd)) {
            onSkill();
            skillCount--;
            skillTimer.capture();
        }
    }


    public abstract void onShoot();

    public abstract void onSkill();

    public static BaseTankComponent getTankComponent(Entity entity) {
        Optional<?> optional = entity.getComponentOptional(PlayerComponent.class);
        if (optional.isPresent()) {
            return (BaseTankComponent) optional.get();
        }
        optional = entity.getComponentOptional(EnemyComponent.class);
        return (BaseTankComponent) optional.orElse(null);
    }

}
